"""
创建装饰器时保留函数元信息

问题：
    你写了一个装饰器作用在某个函数上，但是这个函数的重要的元信息比如名字、文档字符串、注解和参数签名都丢失了。
解决方案：
    任何时候你定义装饰器的时候，都应该使用 functools 库中的 @wraps 装饰器来注解底层包装函数。
"""

import time
from functools import wraps


def compute_time(func):
    """
    计时装饰器函数（正确的示范）
    :param func:
    :return:
    """

    @wraps(func)
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print(func.__name__, end_time - start_time)
        return result

    return wrapper


def compute_time_ex(func):
    """
    计时装饰器函数（错误的示范）
    :param func:
    :return:
    """

    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print(func.__name__, end_time - start_time)
        return result

    return wrapper


@compute_time
def countdown(n):
    """
    倒数计秒
    :param n:
    :return:
    """
    while n > 0:
        n -= 1


@compute_time_ex
def countdown_ex(n):
    """
    倒数计秒
    :param n:
    :return:
    """
    while n > 0:
        n -= 1


def show_by_success():
    print("正确的示范")
    countdown(1000000)
    print(countdown.__name__)

    from inspect import signature
    print(signature(countdown))
    # 输出结果：
    """
    正确的示范
    countdown 0.1723771095275879
    countdown
    (n)
    """


def show_by_error():
    print("错误的示范")
    countdown_ex(1000000)
    print(countdown_ex.__name__)
    # 输出结果：
    """
    错误的示范（丢失函数元信息）
    countdown_ex 0.14860010147094727
    wrapper
    """


if __name__ == "__main__":
    show_by_success()
    show_by_error()
